﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FCS
{
    public abstract partial class Functional
    {
        #region IntList

        public static IFunList<int> IntList(int from)
        {
            return new IntList(from);
        }
        public static IFunList<int> IntList(int from, int to)
        {
            return new IntList(from, to);
        }

        #endregion

        #region Empty

        public static IFunList<T> Empty<T>()
        {
            return new Empty<T>();
        }

        public static IFunList<IFunList<T>> EmptyLL<T>()
        {
            return new EmptyLL<T>();
        }

        #endregion

        #region Comparison

        public static bool Equals<T>(T op1, T op2)
        {
            return op1.Equals(op2);
        }

        #endregion

        #region Output

        public static void Output<T>(T v)
        {
            //if (v != null)
            //{
            //    string name = typeof(IFunList<T>).Name;
            //    string nameSpace = typeof(IFunList<T>).Namespace;
            //    if (v.GetType().GetInterfaces().ToList().Exists(t => t.Name == name && t.Namespace == nameSpace))
            //    {
            //        Output<T>((IFunList<T>)v);
            //    }
            //    else
            //    {
                    new Output<T>(v);
            //    }
            //}
        }
        public static void Output<T>(IFunList<T> l)
        {
            new Output<T>(l);
        }

        #endregion

        #region Maps & Filters

        public static IFunList<U> Map<T, U>(FunUnary<T, U> action, IFunList<T> list)
        {
            return new Map<T, U>(action, list);
        }
        public static IFunList<U> Map<T, U>(FunUnaryIdx<T, U> action, IFunList<T> list)
        {
            return new Map<T, U>(action, list);
        }

        public static IFunList<IFunList<U>> MapV2L<T, U>(FunUnaryL<T, U> action, IFunList<T> list)
        {
            return new MapV2L<T, U>(action, list);
        }

        public static IFunList<IFunList<U>> MapL2L<T, U>(FunUnaryL<IFunList<T>, IFunList<U>> action, IFunList<IFunList<T>> list)
        {
            return new MapL2L<T, U>(action, list);
        }

        public static IFunList<T> Filter<T>(FunPredicate<T> pred, IFunList<T> list)
        {
            return new Filter<T>(pred, list);
        }
        public static IFunList<T> Filter<T>(FunPredicateIdx<T> pred, IFunList<T> list)
        {
            return new Filter<T>(pred, list);
        }

        public static IFunList<T> Filter2<T>(FunPredicate2<T> pred, T against, IFunList<T> list)
        {
            return new Filter2<T>(pred, against, list);
        }
        public static IFunList<T> Filter2<T>(FunPredicate2Idx<T> pred, T against, IFunList<T> list)
        {
            return new Filter2<T>(pred, against, list);
        }

        #endregion

        #region Folds

        public static T Foldl<T>(FunBinary<T> action, T identity, IFunList<T> list)
        {
            return new Foldl<T>(action, identity, list).First();
        }

        public static T Foldr<T>(FunBinary<T> action, T identity, IFunList<T> list)
        {
            return new Foldr<T>(action, identity, list).First();
        }

        #endregion

        #region List queries

        public static T HeadValue<T>(IFunList<T> list)
        {
            return new Head<T>(list).Value;
        }
        public static IFunList<T> Head<T>(IFunList<T> list)
        {
            return new Head<T>(list);
        }
        public static bool IsEmpty<T>(IFunList<T> list)
        {
            return new IsEmpty<T>(list).Value;
        }
        public static T At<T>(int idx, IFunList<T> list)
        {
            return new At<T>(idx, list).Value;
        }

        public static IFunList<T> Tail<T>(IFunList<T> list)
        {
            return new Tail<T>(list);
        }

        public static IFunList<T> Take<T>(int count, IFunList<T> list)
        {
            return new Take<T>(count, list);
        }

        public static int Length<T>(IFunList<T> list)
        {
            return list.Count();
        }

        #endregion
        
        #region List compositions

        public static IFunList<T> ToList<T>(T first)
        {
            return new ToList<T>(first);
        }

        public static IFunList<T> Cons<T>(T first, IFunList<T> tail)
        {
            return new Cons<T>(first, tail);
        }
        public static IFunList<IFunList<T>> ConsL<T>(IFunList<T> firsts, IFunList<T> tail)
        {
            return new ConsL<T>(firsts, tail);
        }

        public static IFunList<T> Compose<T>(IFunList<T> first, IFunList<T> second)
        {
            return new Compose<T>(first, second);
        }
        public static IFunList<T> Compose<T>(IFunList<T> first, T second)
        {
            return new Compose<T>(first, second);
        }

        public static IFunList<T> ListFromArray<T>(params T[] list)
        {
            return new FromArrayList<T>(list);
        }

        #endregion

        #region Perform and Persist list to nonlazy store

        public static void Perform<T>(FunAction<T> act, IFunList<T> list)
        {
            new Perform<T>(act, list);
        }
        public static IFunList<T> Persist<T>(IFunList<T> list)
        {
            return new Persist<T>(list);
        }
        
	    #endregion    
    }
}
